package com.pig4cloud.pigx.auth.config;

import com.pig4cloud.pigx.common.security.component.PigxJdbcClientDetailsServiceImpl;
import com.pig4cloud.pigx.common.security.component.exceptionProcessed.PigxWebResponseExceptionTranslator;
import com.pig4cloud.pigx.common.security.constant.SecurityConstants;
import com.pig4cloud.pigx.common.security.grant.ResourceOwnerCustomeAppTokenGranter;
import com.pig4cloud.pigx.common.security.service.PigxUserDetailsService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;

import javax.sql.DataSource;
import java.util.ArrayList;
import java.util.Arrays;


/**
 * @description:
 * @Author 兔子不吃窝边曹
 * @create 2022/7/15 17:22
 **/
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    private final DataSource dataSource;

    private final AuthenticationManager authenticationManager;

    private final PigxUserDetailsService pigxDefaultUserDetailsServiceImpl;

    private final TokenStore redisTokenStore;

    private final TokenEnhancer tokenEnhancer;

    /**
     * 数据库中配置客户端
     * 注入dataSource数据源，指定SelectClientDetailsSql和FindClientDetailsSql
     *
     * @param clients
     */
    @Override
    @SneakyThrows
    public void configure(ClientDetailsServiceConfigurer clients) {
        PigxJdbcClientDetailsServiceImpl clientDetailsService = new PigxJdbcClientDetailsServiceImpl(dataSource);
        clientDetailsService.setSelectClientDetailsSql(SecurityConstants.DEFAULT_SELECT_STATEMENT);
        clientDetailsService.setFindClientDetailsSql(SecurityConstants.DEFAULT_FIND_STATEMENT);
        clients.withClientDetails(clientDetailsService);
    }

    /**
     * 内存中配置客户端
     *
     * @param clients
     */
//    @Override
//    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients
//                // 配置内存中
//                .inMemory()
//                // 该客户端id
//                .withClient("client_1")
//                // 该客户端密钥
//                .secret("{noop}" + "client_1_secret")
//                // 该客户端token有效时间（秒）
//                .accessTokenValiditySeconds(604800)
//                // 该客户端支持的模式
//                .authorizedGrantTypes("refresh_token", "password", "authorization_code", "implicit")
//                // 该客户端允许的授权范围配置
//                .scopes("userInfo", "server", "all")
//                // 该客户端资源列表
//                .resourceIds("resource")
//                // false 允许跳转到授权页面
//                .autoApprove(false)
//                // 该客户端验证回调地址
//                .redirectUris("http://www.baidu.com");
//
//    }
    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
        oauthServer
                .allowFormAuthenticationForClients() // 允许客户端的表单身份验证
                .checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .tokenStore(redisTokenStore)
                .userDetailsService(pigxDefaultUserDetailsServiceImpl)
                .authenticationManager(authenticationManager)
                .tokenEnhancer(tokenEnhancer)
                .exceptionTranslator(new PigxWebResponseExceptionTranslator())
        ;

        // 注入自定义认证类型
        setTokenGranter(endpoints);
    }

    /**
     * 自定义 APP 认证类型
     *
     * @param endpoints AuthorizationServerEndpointsConfigurer
     */
    private void setTokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
        // 获取默认tokenGranter集合
        TokenGranter tokenGranter = endpoints.getTokenGranter();
        ArrayList<TokenGranter> tokenGranters = new ArrayList<>(Arrays.asList(tokenGranter));

        ResourceOwnerCustomeAppTokenGranter resourceOwnerCustomeAppTokenGranter = new ResourceOwnerCustomeAppTokenGranter(
                authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(),
                endpoints.getOAuth2RequestFactory());
        tokenGranters.add(resourceOwnerCustomeAppTokenGranter);

        // 组合tokenGranter集合
        CompositeTokenGranter compositeTokenGranter = new CompositeTokenGranter(tokenGranters);
        endpoints.tokenGranter(compositeTokenGranter);
    }
}
